"use strict";

process.chdir(__dirname);

const titbit = require("titbit"); //会去上级目录寻找
const fs = require("fs");
const dbcfg = require("./dbconfig.js");
const pg = require("pg");
const wxkey = require("./wxkey.js");
const { httpcli } = require("gohttp");
const token = require("titbit-token");

try {
    fs.accessSync("./images");
} catch (e) {
    fs.mkdirSync("./images");
}

let psql = new pg.Pool(dbcfg);

let cert_path = "/usr/local/share";

const app = new titbit({
    // 开启测试模式,若有错误会输出错误信息
    debug: true,
    // 开启全局日志
    globalLog: true,
    cert: `${cert_path}/api.hiehie.top.pem`,
    key: `${cert_path}/api.hiehie.top.key`,
});

// 添加路由,必须要是async否则会抛出错误
app.get("/", async (c) => {
    c.send("ok");
});

/************************************content路由*********************************************/

// 获取内容列表
app.get("/content", async (c) => {
    let ret = await psql.query("select * from content");

    // 等效于c.res.body=ret.rows
    c.send(ret.rows);
});

// 获取具体内容
app.get("/content/:id", async (c) => {
    let sqltext = `SELECT * FROM content WHERE id=$1`;
    let r = await psql.query(sqltext, [c.param.id]);
    if (r.rowCount === 0) {
        return c.status(404).send("content not found");
    }
    c.send(r.rows[0]);
});

// 创建内容
app.post("/content", async (c) => {
    try {
        // 提交的body数据通过c.body获取
        let data = JSON.parse(c.body);
        let sqltext =
            `INSERT INTO content(id,add_time,detail,title,update_time)` +
            ` VALUES ($1,$2,$3,$4,$5)`;

        /*  text/* :c.body string 
        multipart: c.body={}  c.files={} 
        others:c.body=c.rawBody(buffer类型) */

        //生成唯一ID
        let id = c.helper.makeId();
        let tm = Date.now();
        let r = await psql.query(sqltext, [id, tm, data.detail, data.title, tm]);

        if (r.rowCount === 0) {
            return c.status(500).send("failed");
        }
        c.send(id);
    } catch (err) {
        c.status(404).send("it is not json data");
    }
});

// 删除内容
app.delete("/content/:id", async (c) => {
    let sqltext = `DELETE FROM content WHERE id=$1`;
    let r = await psql.query(sqltext, [c.param.id]);
    if (r.rowCount === 0) {
        c.send(r);
    }
});

/************************************content路由 - END*********************************************/

app.get("/upload", async (c) => {
    await c.helper.pipe("./upload.html", c.reply); //提供好的模块,可以直接用
    // c.reply在http1中指向的是res,在http2中指向stream
    // c.reply是响应对象,可写的流
});
app.post("/upload", async (c) => {
    // 根据name获取文件对象
    let f = c.getFile("image");
    if (!f) {
        return c.status(400).send("image is not found");
    }

    // 根据传入的原始文件名生成唯一文件名,主要是用f.filename的扩展名
    let fname = c.helper.makeName(f.filename);

    // 移动文件到指定位置
    await c.moveFile(f, `./images/${fname}`);

    c.send(fname);
});

// 返回图片数据
// :表示:name是动态变化的
app.get("/image/:name", async (c) => {
    // c.param是一个对象,其中的key值是路由参数的名称
    let imgname = c.param.name;

    await c.helper.pipe(`./images/${imgname}`, c.reply);
});

let tok = new token({
    // 解密时的一个超时验证，45秒超时，token有效期，单位为秒
    expires: 60,
    // 必须是32位字符
    key: "qwertyuiopasdfghjklzxcvbnm<>?123",
    // 必须是16位字符
    iv: "1qaz2wsx3edc4rfv",
});
app.get("/mp-login/:code", async (c) => {
    let auth_url =
        `https://api.weixin.qq.com/sns/jscode2session` +
        `?appid=${wxkey.appid}` +
        `&secret=${wxkey.secret}` +
        `&js_code=${c.param.code}` +
        `&grant_type=authorization_code`;
    let ret = await httpcli.get(auth_url).then((res) => {
        return res.json();
    });
    c.send(tok.make(ret));
});

app.get("/decrypt/:token", async (c) => {
    c.send(tok.verify(c.param.token));
});

// 运行在1234窗口
app.run(2346);

/**
 * HTTP 消息头 content-type 制订了数据的类型（数据的格式）
 *
 * Client
 * content-type描述的值
 * 要和提交的body数据一致
 *
 *
 * Server
 * 根据content-type 的值决定如何解析Body数据
 *
 * content-type:
 * multipart/form-data;boundary=xxx -----文件解析
 *
 * text/* -------文本类型
 *
 * application/*  ------ 要看具体值，application/json也是文本类型
 *
 * ......   --------   每种类型如何处理是双方设计好的通信方式
 *
 * 到Web框架这一层面，如何处理是开发框架设计好的，但通常都要遵循一个原则，
 * 允许开发者做自己的处理
 *
 * 在本框架范围内：
 * multipart类型  c.body是Object类型，文件信息解析到c.files。
 *
 * application/x-www-form-urlencoded 传统的表单类型，
 *      c.body是Object类型，用于获取提交的表单数据
 *
 * text/*  c.body 是文本类型，c.body = c.rawBody.toString('utf8')。
 *
 * 其他类型： c.body 是buffer类型，就是对c.rawBody的引用。
 *
 *
 *
 *
 *
 *
 */
